package com.szcinda.rpa.service;

import com.szcinda.rpa.netty.NettyChannelInboundHandlerAdapter;
import com.szcinda.rpa.repository.UserMachine;
import com.szcinda.rpa.repository.UserMachineRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static com.szcinda.rpa.netty.NettyChannelInboundHandlerAdapter.RUN_TASK_MAP;

@Service
@Transactional
public class UserMachineServiceImpl implements UserMachineService {
    private final UserMachineRepository userMachineRepository;
    private final SnowFlakeFactory snowFlakeFactory;


    public UserMachineServiceImpl(UserMachineRepository userMachineRepository) {
        this.userMachineRepository = userMachineRepository;
        this.snowFlakeFactory = SnowFlakeFactory.getInstance();
    }

    @Override
    public List<UserMachineDto> getMachineByUserName(String userName) {
        List<UserMachine> userMachines;
        boolean isAdmin = "admin".equals(userName);
        ConcurrentHashMap<String, List<String>> map = NettyChannelInboundHandlerAdapter.FLOW_MAP;
        if (!isAdmin) {
            userMachines = userMachineRepository.findByUserName(userName);
            Enumeration<String> keys = map.keys();
            List<UserMachine> needToCreateList = new ArrayList<>();
            while (keys.hasMoreElements()) {
                String key = keys.nextElement();
                if (key.contains(userName)) {
                    String[] array = key.split("#");
                    if (userMachines.stream().noneMatch(userMachine -> userMachine.getIp().equals(array[1]))) {
                        UserMachine userMachine = new UserMachine();
                        userMachine.setId(snowFlakeFactory.nextId());
                        userMachine.setUserName(userName);
                        userMachine.setIp(array[1]);
                        needToCreateList.add(userMachine);
                    }
                }
            }
            if (needToCreateList.size() > 0) {
                userMachineRepository.saveAll(needToCreateList);
            }
        }
        if (isAdmin) {
            userMachines = userMachineRepository.findAll();
        } else {
            userMachines = userMachineRepository.findByUserName(userName);
        }
        ConcurrentHashMap<String, LocalDateTime> machineStatusMap = NettyChannelInboundHandlerAdapter.MACHINE_STATUS_MAP;
        List<UserMachineDto> userMachineDtos = new ArrayList<>();
        userMachines.forEach(userMachine -> {
            if (isAdmin) {
                UserMachineDto dto = new UserMachineDto();
                BeanUtils.copyProperties(userMachine, dto);
                if (map.containsKey(userMachine.getUserName() + "#" + dto.getIp())) {
                    List<String> list = map.get(userMachine.getUserName() + "#" + dto.getIp());
                    if (list != null && list.size() > 0) {
                        dto.setFlows(list);
                    }
                }
                if (machineStatusMap.containsKey(userMachine.getUserName() + "#" + dto.getIp())) {
                    dto.setLocalDateTime(machineStatusMap.get(userMachine.getUserName() + "#" + dto.getIp()));
                }
                userMachineDtos.add(dto);
            } else {
                UserMachineDto dto = new UserMachineDto();
                BeanUtils.copyProperties(userMachine, dto);
                if (map.containsKey(userName + "#" + dto.getIp())) {
                    List<String> list = map.get(userName + "#" + dto.getIp());
                    if (list != null && list.size() > 0) {
                        dto.setFlows(list);
                    }
                }
                if (machineStatusMap.containsKey(userName + "#" + dto.getIp())) {
                    dto.setLocalDateTime(machineStatusMap.get(userName + "#" + dto.getIp()));
                }
                userMachineDtos.add(dto);
            }
        });
        return userMachineDtos;
    }

    @Override
    public List<RunTask> getRunTasks(String userName) {
        List<RunTask> runTasks = new ArrayList<>();
        boolean isAdmin = "admin".equals(userName);
        Enumeration<String> keys = RUN_TASK_MAP.keys();
        while (keys.hasMoreElements()) {
            String key = keys.nextElement();
            if (isAdmin) {
                String[] array = key.split("#");
                RunTask task = new RunTask();
                task.setUserName(array[0]);
                task.setIp(array[1]);
                task.setName(array[2]);
                runTasks.add(task);
            } else if (key.contains(userName)) {
                String[] array = key.split("#");
                RunTask task = new RunTask();
                task.setUserName(userName);
                task.setIp(array[1]);
                task.setName(array[2]);
                runTasks.add(task);
            }
        }
        if (runTasks.size() > 0) {
            runTasks.forEach(runTask -> {
                String key;
                if (isAdmin) {
                    key = runTask.getUserName() + "#" + runTask.getIp() + "#" + runTask.getName();
                } else {
                    key = userName + "#" + runTask.getIp() + "#" + runTask.getName();
                }
                LocalDateTime localDateTime = RUN_TASK_MAP.get(key);
                if (NettyChannelInboundHandlerAdapter.errorQueue.contains(key)) {
                    runTask.setStatus("(运行出错)");
                }
                runTask.setLocalDateTime(localDateTime);
            });
        }
        return runTasks;
    }

    @Override
    public void run(RunTask runTask) {
        RUN_TASK_MAP.put(runTask.getUserName() + "#" + runTask.getIp() + "#" + runTask.getName(), LocalDateTime.now());
    }

    @Override
    public void stop(RunTask runTask) {
        RUN_TASK_MAP.remove(runTask.getUserName() + "#" + runTask.getIp() + "#" + runTask.getName());
    }

    @Override
    public void delete(String id) {
        userMachineRepository.deleteById(id);
    }
}
